from flask import current_app
from flask import g, jsonify
from flask import redirect
from flask import render_template
from flask import request
from flask import session
from flask import url_for
from sqlalchemy import not_

from info import constants
from info import db
from info.models import News, Category, User
from info.modules.utils.common import user_login_data
from info.modules.utils.file_storage import upload
from info.modules.utils.response_code import RET

from info.modules.user import user_blu


# 用户信息
@user_blu.route("/user_info")
@user_login_data
def user_info():
    """
    用户信息主页
    :return: render_template("news/user.html", data=data)
    """
    user = g.user
    if not user:
        return redirect(url_for("index.index"))
    # 组装数据
    data = {
        "user_info": g.user.to_dict()
    }
    return render_template("news/user.html", data=data)


# 基本资料
@user_blu.route("/base_info", methods=["GET", "POST"])
@user_login_data
def base_info():
    user = g.user
    if not user:
        return redirect(url_for('index.index'))

    # 请求user_base_info 页面 GET

    if request.method == "GET":
        data = {
            "user_info": g.user.to_dict()
        }
        return render_template("news/user_base_info.html", data=data)

    if request.method == "POST":

        # 1. 接收参数nick_name signature gender
        json_data = request.json
        nick_name = json_data.get("nick_name")
        signature = json_data.get("signature")
        gender = json_data.get("gender")

        # 2. 校验参数
        if not all([nick_name, signature, gender]):
            return jsonify(errno=RET.PARAMERR, errmsg="参数不全")

        if gender not in ["MAN", "WOMAN"]:
            return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

        # 3. 修改用户数据
        try:
            user.nick_name = nick_name
            user.gender = gender
            user.signature = signature
            db.session.commit()
        except Exception as e:
            current_app.logger.err(e)
            db.session.rollback()

        # 4. 重新修改状态保持数据,很重要
        session["nick_name"] = nick_name

        # 5. 返回数据
        return jsonify(errno=RET.OK, errmsg="操作成功")


# 修改头像
@user_blu.route("/pic_info", methods=["GET", "POST"])
@user_login_data
def pic_info():
    """
    修改头像
    :return:
    """
    user = g.user
    if not user:
        return redirect(url_for("index.index"))

    if request.method == "GET":
        data = {
            "user_info": user.to_dict()
        }
        return render_template("news/user_pic_info.html", data=data)

    if request.method == "POST":
        # 获取文件,读取文件二进制数据
        pic_bytes = request.files.get("avatar").read()
        try:
            key = upload(pic_bytes)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.THIRDERR, errmsg="头像上传失败")

        # 修改用户头像数据
        user.avatar_url = key
        try:
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="数据库更新头像失败")

        avatar_url = constants.QINIU_DOMIN_PREFIX + key
        data = {
            "avatar_url": avatar_url
        }
        return jsonify(errno=RET.OK, errmsg="OK", data=data)


# 我的关注
@user_blu.route("/user_follow", methods=["GET"])
@user_login_data
def user_follow():
    """我的关注信息"""
    user = g.user
    if not user:
        return redirect(url_for("index.index"))
    # 1. 接收校验参数
    current_page = request.args.get("page")
    if not current_page:
        current_page = 1

    try:
        current_page = int(current_page)
    except Exception as e:
        current_page = 1

    total_page = 1

    # 查询user的关注用户
    try:
        paginate = user.followed.paginate(current_page, constants.USER_FOLLOWED_MAX_COUNT, False)
    except Exception as e:
        current_app.logger.error(e)
        paginate = None

    # 构造数据
    followed_users = []
    if paginate:
        current_page = paginate.page
        total_page = paginate.pages
        followed_users = paginate.items

    followed_users_dict = []
    for user in followed_users:
        followed_users_dict.append(user.to_dict())

    data = {
        "current_page": current_page,
        "total_page": total_page,
        "followed_users": followed_users_dict
    }

    return render_template("news/user_follow.html", data=data)


# 密码
@user_blu.route("/pass_info", methods=["GET", "POST"])
@user_login_data
def pass_info():
    """修改密码"""

    user = g.user

    # 1. 判断用户是否登录
    if not user:
        return redirect(url_for("index.index"))

    # 2. GET 请求
    if request.method == "GET":
        data = {
            "user_info": user.to_dict() if user else None
        }
        return render_template("news/user_pass_info.html", data=data)

    # 3. 修改密码
    if request.method == "POST":
        # 3.1. 获取参数 old_password new_password 校验参数
        json_data = request.json
        old_password = json_data.get("old_password")
        new_password = json_data.get("new_password")

        if not all([old_password, new_password]):
            return jsonify(errno=RET.PARAMERR, errmsg="缺少参数")

        # 3.2 修改用户信息
        if user.check_password(old_password):
            try:
                user.password = new_password
                db.session.commit()
            except Exception as e:
                current_app.logger.error(e)
                db.session.rollback()
                return jsonify(errno=RET.DBERR, errmsg="更新密码失败")
        else:
            return jsonify(errno=RET.PWDERR, errmsg="输入密码错误")

        # 3.3 响应消息
        return jsonify(errno="0", errmsg="操作成功")


# 收藏
@user_blu.route("/collection", methods=["GET"])
@user_login_data
def collection():
    """新闻收藏"""
    user = g.user
    if not user:
        return redirect(url_for("index.index"))
    # if not user:
    #     data = {
    #         "total_page": 1,
    #         "current_page": 1,
    #         "collections": [],
    #     }
    #     return render_template("news/user_collection.html", data=data)

    # 请求第几页 page
    page = request.args.get("page", 1)

    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        page = 1

    total_page = 1
    current_page = 1
    # 查询所有收藏的新闻
    collect_news = []
    try:
        # collection_news 是一个关系属性,它是一个BaseQuery对象吗,看来是的
        paginate = user.collection_news.paginate(page, constants.USER_COLLECTION_MAX_NEWS, False)
        collect_news = paginate.items
        total_page = paginate.pages
        current_page = paginate.page
    except Exception as e:
        current_app.logger.error(e)

    collect_news_list = []
    for news in collect_news:
        collect_news_list.append(news.to_basic_dict())

    data = {
        "total_page": total_page,
        "current_page": current_page,
        "collections": collect_news_list
    }

    return render_template("news/user_collection.html", data=data)


# 发布
@user_blu.route("/news_release", methods=["GET", "POST"])
@user_login_data
def news_release():
    """
    发布新闻
    :return:
    """
    user = g.user
    if not user:
        return redirect("index.index")

    # GET请求, 获取新闻分类
    if request.method == "GET":
        try:
            categories = Category.query.filter(not_(Category.id == 1)).order_by(Category.id.asc())
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="新闻分类读取失败")

        data = {
            "user_info": g.user.to_dict() if g.user else None,
            "categories": categories
        }
        return render_template("news/user_news_release.html", data=data)

    # POST, 发布新闻
    if request.method == "POST":
        # 1. 获取数据title category_id digest index_image content
        title = request.form.get("title")
        category_id = request.form.get("category_id")
        digest = request.form.get("digest")
        index_image = request.files.get("index_image").read()
        content = request.form.get("content")

        source = "个人发布"
        status = 1

        # 2. 校验数据
        if not all([title, category_id, digest, index_image, content]):
            return jsonify(errno=RET.PARAMERR, errmsg="参数不全")

        try:
            category_id = int(category_id)
        except Exception as e:
            current_app.logger(e)
            return jsonify(errno=RET.PARAMERR, errmsg="数据错误")

        # 3. 向七牛云上传图片
        try:
            key = upload(index_image)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.THIRDERR, errmsg="新闻图片上传失败")

        # 4. 创建新闻  提交数据
        news = News()
        news.title = title
        news.category_id = category_id
        news.digest = digest
        # 此处必须加,因为数据库中新闻图片地址都有自己的前缀
        news.index_image_url = constants.QINIU_DOMIN_PREFIX + key
        news.content = content
        news.source = source
        news.user_id = user.id
        news.status = status

        try:
            db.session.add(news)
            db.session.commit()
        except Exception as e:
            current_app.logger.err(e)
            db.session.rollback()
            return jsonify(errno=RET.DBERR, errmsg="新闻上传失败")

        # 4.响应结论
        return jsonify(errno=RET.OK, errmsg="操作成功")


# 用户新闻列表
@user_blu.route("/news_list", methods=["GET"])
@user_login_data
def news_list():
    user = g.user
    if not user:
        return redirect(url_for("index.index"))

    # 1. 获取 校验 参数 获取第几页 page
    page = request.args.get("page")
    if page:
        try:
            page = int(page)
        except Exception as e:
            current_app.logger.error(e)
            page = 1

    # 2. 查询当前用户发布的所有新闻
    try:
        paginate = News.query.filter(News.user_id==user.id).order_by(News.create_time.desc()).\
            paginate(page, constants.USER_COLLECTION_MAX_NEWS, False)
    except Exception as e:
        current_app.logger.error(e)
        paginate = None

    # 组装数据
    if paginate:
        news_list = paginate.items
        current_page = paginate.page
        total_page = paginate.pages
    else:
        news_list = []
        current_page = 1
        total_page = 1
    news_dict_list = []
    for news in news_list:
        news_dict_list.append(news.to_review_dict())

    data = {
        "news_list": news_dict_list,
        "current_page": current_page,
        "total_page": total_page
    }

    return render_template("news/user_news_list.html", data=data)


# 其它用户信息
@user_blu.route("/other_info", methods=["GET"])
@user_login_data
def other_info():
    """显示其它用户详情页"""

    user = g.user
    # if request.method == "GET":
    # 获取other的信息
    this_id = request.args.get("this_id")
    try:
        this_user = User.query.get(this_id)
    except Exception as e:
        current_app.logger.error(e)
        # 查询失败重定向用户关注界面
        return redirect(url_for("user.user_follow"))

    if not this_user:
        # 如果other用户不存在,重定向用户关注界面, 如果用户也不存在,重定向index.index
        return redirect(url_for("user.user_follow"))

    # 查询用户是否关注当前作者
    is_follow = False
    # 用户未登录时,默认False
    if not user:
        is_follow = False

    # 如果这个作者在用户的关注人群中 True
    if user:
        if this_user in user.followed:
            is_follow = True

    # 构造数据
    data = {
        "this_user_info": this_user.to_dict() if this_user else None,
        "user_info": user.to_dict() if user else None,
        "is_follow": is_follow
    }
    # GET显示响应
    return render_template("news/other.html", data=data)


# 其它用户界面,进行关注和取消关注
@user_blu.route("/other_follow", methods=["POST"])
@user_login_data
def other_follow():
    """其它用户界面的关注和取消关注处理"""
    user = g.user

    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="关注前请先登录")

    # 1 接收参数 user_id(新闻发布者), action in ["follow", "unfollow"]
    author_id = request.json.get("user_id")
    action = request.json.get("action")

    # 2 校验参数
    if not all([author_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg="缺少参数")

    if action not in ["follow", "unfollow"]:
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    try:
        author = User.query.get(author_id)
        user_followed = user.followed
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据查询错误")

    if not author:
        return jsonify(errno=RET.NODATA, errmsg="该关注的用户不存在")

    if user.id == author.id:
        return jsonify(errno=RET.USERERR, errmsg="不能关注自己")

    # 3 进行关注处理
    if action == "follow":
        if author not in user_followed:
            user_followed.append(author)
    else:
        if author in user_followed:
            user_followed.remove(author)

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="数据库修改失败")

    # 4 响应结果
    return jsonify(errno=RET.OK, errmsg="操作成功")

# 其它用户界面,显示其发布的新闻
@user_blu.route("/other_news")
def other_news():
    """显示当前作者发布的新闻"""

    # 1. 获取参数 current_page, user_id, pre_page,
    user_id = request.args.get("user_id")
    page = request.args.get("p")
    pre_page = request.args.get("pre_page", constants.OTHER_NEWS_PAGE_MAX_COUNT)

    # 2. 校验参数
    if not all([user_id, current_app, pre_page]):
        return jsonify(errno=RET.PARAMERR, errmsg="缺少参数")

    try:
        user_id = int(user_id)
        page = int(page)
        pre_page = int(pre_page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    try:
        author = User.query.get(user_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库查询错误")

    if not author:
        return jsonify(errno=RET.USERERR, errmsg="该作者不存在")

    # 3. 查询该作者的发布的,审核通过的,按时间顺序倒序排列
    try:
        paginate = News.query.filter(News.user_id==user_id, News.status==0).order_by(News.create_time.desc()).paginate(page, pre_page, False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="该用户发布的新闻查询失败")

    # 4. 构造数据
    news_dict_list = []
    news_author = paginate.items
    for news in news_author:
        news_dict_list.append(news.to_dict())

    data = {
        "news_list": news_dict_list,
        "current_page": paginate.page,
        "total_page": paginate.pages,
    }
    return jsonify(errno=RET.OK, errmsg="OK", data=data)
